<?php

namespace app\services\user;

use app\dao\user\UserDao;
use app\services\BaseService;
use exceptions\AdminException;
use exceptions\ApiException;
use exceptions\AuthException;
use services\CacheService;
use think\exception\ValidateException;
use utils\JwtAuth;

/**
 * Class User
 * @package app\services\user
 */
class UserService extends BaseService
{
    /**
     * 不导出的字段信息
     * @var array
     */
    protected $noExportFields = ['delete_time', 'update_time', 'is_del'];

    public function __construct(UserDao $dao)
    {
        $this->dao = $dao;
    }

    public function getSexList()
    {
        return ['1' => '男', '2' => '女'];
    }

    public function getIsDisableList()
    {
        return ['1' => '正常', '0' => '冻结'];
    }

    /**
     * Description: 获取分页列表
     *
     * @param array $where
     *
     * @return array
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     */
    public function getSysList(array $where)
    {
        [$page, $limit] = $this->getPageValue();
        $data  = $this->dao->queryList($where, $page, $limit);
        $count = $this->dao->count($where);
        return compact('data', 'count');
    }

    public function parseToken($token): array
    {
        $md5Token = is_null($token) ? '' : md5($token);

        if ($token === 'undefined') {
            throw new AuthException('请登录', 410000);
        }
        if (!$token) {
            throw new AuthException('请登录', 410000);
        }

        /** @var JwtAuth $jwtAuth */
        $jwtAuth = app()->make(JwtAuth::class);
        //设置解析token
        [$id, $type] = $jwtAuth->parseToken($token);

        $tokenData = CacheService::getTokenBucket($id . '_user_token');

        if (!is_array($tokenData) || empty($tokenData) || !isset($tokenData['uid'])) {
            throw new AuthException('请登录', 410000);
        }
        try {
            $jwtAuth->verifyToken();
        } catch (\Throwable $e) {
            CacheService::clearToken($md5Token);
            throw new AuthException('登录已过期,请重新登录', 410001);
        }

        $user = $this->dao->get($id);
        if (!$user || $user->id != $tokenData['uid']) {
            // CacheService::clearToken($md5Token);
            throw new AuthException('登录状态有误,请重新登录', 410002);
        }
        $user->uid         = $user->id;
        $tokenData['type'] = $type;
        return compact('user', 'tokenData');
    }

    /**
     * Description:资料设置
     *
     * @param array $data
     * @param       $uid
     *
     * @return bool
     */
    public function saveData(array $data, $uid)
    {
        // if (!$data['avatar'] || !$data['nickname'] || !$data['sex'] || !$data['phone'])
        //     throw new ApiException('参数错误');
        if (isset($data['phone']) && !preg_match("/^1[3456789]\d{9}|([0-9]{3,4}-)?[0-9]{7,8}$/", $data['phone']))
            throw new ApiException('手机号格式错误');
        if (isset($data['phone']) && $this->dao->be(['phone' => $data['phone']]))
            throw new ApiException('该手机号已存在');
        if (!$this->dao->update($uid, $data))
            throw new ApiException('资料设置失败');
        return true;
    }

    public function login(string $account, string $inviteCode = '')
    {
        $user = $this->dao->getOne(['account|phone' => $account]);
        // 如果用户第一次登录则直接注册
        if ($user->isEmpty()) {
            $user = $this->createUser($account, $inviteCode);
        } else {
            if (!$user['is_disable']) {
                throw new ValidateException('已被冻结，请联系管理员');
            }
            //更新用户信息
            $this->updateUserInfo(['code' => $inviteCode], $user);
        }

        $token = $this->createToken((int)$user['id'], 'api');
        if (!$token) {
            throw new ValidateException('登录失败');
        }
        return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
    }

    public function updateUserInfo($user, $userInfo)
    {
        $data              = [];
        $data['nickname']  = !isset($user['nickname']) || !$user['nickname'] ? $userInfo->nickname : $user['nickname'];
        $data['avatar']    = !isset($user['headimgurl']) || !$user['headimgurl'] ? $userInfo->avatar : $user['headimgurl'];
        $data['phone']     = !isset($user['phone']) || !$user['phone'] ? $userInfo->phone : $user['phone'];
        $data['last_time'] = time();
        $data['last_ip']   = app()->request->ip();
        if ($userInfo->spread_uid) {
            $data['login_type'] = $user['login_type'] ?? $userInfo->login_type;
        } else {
            //绑定分销关系 = 所有用户
            if (sysconfig('brokerage_bindind', 1) == 1) {
                $inviteCode = isset($user['code']) && $user['code'] ? $user['code'] : 0;
                $spreadUid  = $this->dao->value(['invite_code' => $inviteCode], 'id');
                if ($spreadUid) {
                    $spreadUid           = (int)$spreadUid;
                    $data['spread_uid']  = $spreadUid;
                    $data['spread_time'] = $userInfo->last_time;
                    $this->dao->incField($spreadUid, 'spread_count');
                    //绑定成功发送消息
                    /** @var  WechatUserService $wechatServices */
                    /*$wechatServices = app()->make(WechatUserServices::class);
                    if (strtolower($userInfo->user_type) == 'routine') {
                        $openid = $wechatServices->uidToOpenid($spreadUid, 'routine');
                        Queue::instance()->do('sendBindSpreadUidSuccess')->job(RoutineTemplateJob::class)->data($openid, $user['nickname'] ?? '')->push();
                    } else {
                        $openid = $wechatServices->uidToOpenid($spreadUid, 'wechat');
                        Queue::instance()->do('sendBindSpreadUidSuccess')->job(TemplateJob::class)->data($openid, $user['nickname'] ?? '')->push();
                    }*/
                }
            }
        }
        if (!$this->dao->update($userInfo['id'], $data, 'id')) {
            throw new ValidateException('修改信息失败');
        }
        return true;
    }

    /**
     * Description: 新增用户
     *
     * @param $phone
     * @param $spread
     *
     * @return mixed
     */
    public function createUser($phone, $spread)
    {
        $data['account'] = $phone;
        $data['pwd']     = md5('123456');
        $data['phone']   = $phone;
        if ($spread) {
            $data['spread_uid']  = $spread;
            $data['spread_time'] = time();
            /** @var UserBillService $userBill */
            $userBill = app()->make(UserBillService::class);
            //邀请新用户增加经验
            $userBill->inviteUserIncExp((int)$spread);
        }
        $data['user_type'] = 'app';
        $data['add_time']  = time();
        $data['add_ip']    = app('request')->ip();
        $data['last_time'] = time();
        $data['last_ip']   = app('request')->ip();
        $data['nickname']  = substr(md5($phone . time()), 0, 12);
        $data['avatar']    = sysconfig('h5_avatar', '');
        $user              = $this->dao->save($data);
        if (!$user) {
            throw new ValidateException('注册失败');
        }
        return $user;
    }

    /**
     * Description:
     *
     * @param        $user
     * @param int    $spreadUid
     * @param string $userType
     *
     * @return mixed
     */
    public function setUserInfo($user, int $spreadUid = 0, string $userType = 'wechat')
    {
        $res = $this->dao->save([
            'account'    => $user['account'] ?? 'wx' . rand(1, 9999) . time(),
            'pwd'        => $user['pwd'] ?? md5('123456'),
            'nickname'   => $user['nickname'] ?? '',
            'avatar'     => $user['headimgurl'] ?? '',
            'phone'      => $user['phone'] ?? '',
            'spread_uid' => $spreadUid,
            'add_time'   => time(),
            'add_ip'     => app()->request->ip(),
            'last_time'  => time(),
            'last_ip'    => app()->request->ip(),
            'user_type'  => $userType
        ]);
        if (!$res)
            throw new AdminException('保存用户信息失败');
        //用户生成后置事件
        // event('user.register', [$spreadUid, $userType, $user['nickname'], $res->uid, 1]);
        return $res;
    }

}